/*
 * Qmss.c
 *
 *  Created on: Oct 13, 2018
 *      Author: ax
 */
#define MODULE "[Qmss]: "

#include <Hw/Qmss.h>
#include <Hw/Memory.h>

#include <ti/csl/cslr_device.h>
#include <ti/csl/cslr_qm_intd.h>
#include <ti/csl/cslr_qm_config.h>
#include <ti/csl/cslr_qm_descriptor_region_config.h>


static Uint32 QDescMax;
static Uint16 QDescIdx;
static Uint16 QDescRegion;

void __init
Qmss_init(
    void*  extLinkRam,
    Uint32 entryNum
){
    CSL_Qm_configRegs* const hQmss
        = (CSL_Qm_configRegs*) CSL_QM_SS_CFG_CONFIG_STARVATION_COUNTER_REGS;

    /** Internal Linking RAM offset */
    hQmss->LINKING_RAM_REGION_0_BASE_ADDRESS_REG = 0x80000;
    /** Internal Linking RAM with default size only */
    hQmss->LINKING_RAM_REGION_0_SIZE_REG
        = (QDescMax = Qmss_INTERNAL_LINK_RAM_DSEC_SUPPORT) - 1;
    if (extLinkRam) {
        hQmss->LINKING_RAM_REGION_1_BASE_ADDRESS_REG = (Uint32) extLinkRam;
        QDescMax += entryNum;
    }

    QDescRegion = QDescIdx = 0;
}

#include <c6x.h>
#include <string.h>

void
Qmss_descriptorSetup(
    PtrVal  base,
    Uint16  num,
    DescSize fsize,
    DescTid type,
    Queue   fdq
){
    assert(QDescRegion < QM_REGIONS);
    assert((base & (QM_MEMR_ALIGN -1)) == 0);
    //assert(fsize < Desc_HOST_FETCH_SIZE_CNT); ?monolithic size
    assert(fsize * num < 128*1024); //region should less than 128KB
    assert((num >= 32) && (num < 1024*1024));
    assert((1 == (_dotpu4(_bitc4(num), 0x01010101))));
    assert(QDescIdx + num < Qmss_INTERNAL_LINK_RAM_DSEC_SUPPORT);

    Uint16 size = (DescSize) Desc_size(fsize);
    Uint16 regSize = 31 - _lmbd(1, num) - 5;

    Log_dbg(MODULE"Setup %s descriptor pool - %d @%x + %d x %d with region-%d, index-%xh \n",
            Descriptor_HOST_PACKET == type ? "Host" : "Monolithic",
                    fdq, base, size, num, QDescRegion, QDescIdx);

    CSL_Qm_descriptor_region_configRegs* const hQmss =
        (CSL_Qm_descriptor_region_configRegs*) CSL_QM_SS_CFG_DESCRIPTION_REGS;

    hQmss->MEMORY_REGION_BASE_ADDRESS_GROUP[QDescRegion].MEMORY_REGION_BASE_ADDRESS_REG = base;
    hQmss->MEMORY_REGION_BASE_ADDRESS_GROUP[QDescRegion].MEMORY_REGION_START_INDEX_REG = QDescIdx;
    hQmss->MEMORY_REGION_BASE_ADDRESS_GROUP[QDescRegion].MEMORY_REGION_DESCRIPTOR_SETUP_REG
       = CSL_FMK(QM_DESCRIPTOR_REGION_CONFIG_MEMORY_REGION_DESCRIPTOR_SETUP_REG_DESC_SIZE, fsize)
       | CSL_FMK(QM_DESCRIPTOR_REGION_CONFIG_MEMORY_REGION_DESCRIPTOR_SETUP_REG_REG_SIZE, regSize);
    QDescRegion++;
    QDescIdx += num;

    for (Uint16 i = 0; i < num; i++) {
        HostDesc hd = (HostDesc) (base + size * i);
        memset(hd, 0, size);
        if ((hd->type_id = type) == Descriptor_HOST_PACKET) {
            hd->return_policy = 1;
            hd->pkt_return_qmgr = QMGR(fdq);
            hd->pkt_return_qnum = QNUM(fdq);
        } else {
            ((MonoDesc) hd)->data_offset = 16;
            ((MonoDesc) hd)->pkt_return_qmgr = QMGR(fdq);
            ((MonoDesc) hd)->pkt_return_qnum = QNUM(fdq);
        }
        Qmss_push(fdq, (Descriptor) hd | fsize);
    }

    Log_dbg("%d in pool.\n", Qmss_getEntryCnt(fdq));
}

Uint16
Qmss_queueSetup(
    Queue     dstQ,
    Queue     srcQ,
    Uint16    num,
    DescSize  fsize,
    bool      epib,
    Uint8     psSize,
    Uint8*    heaps,
    Uint32    buffSize,
    void*     hook
){
    assert((srcQ < Queue_MAX) && (dstQ < Queue_MAX));

    Log_mark(MODULE"Setup Queue-%d from pool-%d with heap @%x + %d x %d: epib-%d psSize-%d.\n",
            dstQ, srcQ, heaps, buffSize, num, epib, psSize);

    Uint16 i;
    for (i = 0; i < num; i++) {
        HostDesc hd = (HostDesc) Qmss_pop(srcQ);
        if (NULL == hd) return i;
        //else
        if (epib)
            hd->epib = 1;
        hd->pkt_return_qmgr = QMGR(dstQ);
        hd->pkt_return_qnum = QNUM(dstQ);
        hd->psv_word_count = psSize;
        if (Descriptor_HOST_PACKET == hd->type_id) {
            hd->buffer_len = hd->orig_buff0_len = buffSize;
            hd->buffer_ptr = hd->orig_buff0_ptr =  (Uint32) heaps;
        } else {
            TODO("Monolithic support");//TODO add Monolithic support
            return i;
        }
        heaps += buffSize;
        if (hook != NULL)
            ((Descriptor_Hook) hook)((Descriptor) hd);

        Qmss_push(dstQ, (Descriptor) hd | fsize);
    }

    return i;
}

void
Qmss_start(
    void
){
    CSL_Qm_intdRegs* const hQmssIntd = (CSL_Qm_intdRegs*) CSL_QM_SS_CFG_INTD_REGS;
    hQmssIntd->STATUS_CLR_REG0 = 0xFFFFFFFF;
    hQmssIntd->STATUS_CLR_REG1 = 0x0000FFFF;
}
